#include <stdio.h>
#include "libdef.h"
#include "util.h"
#include "file_png.h"

PNG *LoadPNG(const char *path)
{
	FILE *f;
	long lSize;
	BYTE *buffer;
	PNG *png;

	PNG *Convert(BYTE*, const long);

	f = fopen(path, "rb");
	if(f == NULL)
	{
		printf("Error in loading file.");
		return NULL;
	}

	fseek(f, 0, SEEK_END);
	lSize = ftell(f);
	rewind(f);

	buffer = (BYTE*)SafeMalloc(sizeof(BYTE)  *lSize);

	fread(buffer, 1, lSize, f);

	fclose(f);

	png = Convert(buffer, lSize);

	free(buffer);
	return png;
}

static PNG *Convert(BYTE *buffer, const long size)
{
	size_t cur;
	PNG *png;
	ChunkList *curList;
	ChunkList *GetChunk(BYTE *, size_t *);
	BYTE pngSig[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};

	for(cur = 0; cur < 8; cur++)
	{
		if(pngSig[cur] != buffer[cur])
			return NULL;
	}

	png = (PNG*)SafeMalloc(sizeof(PNG));

	curList = GetChunk(buffer, &cur);
	png->head = curList;

	while(cur < size)
		curList = curList->next = GetChunk(buffer, &cur);

	return png;
}

static ChunkList *GetChunk(BYTE *buffer, size_t *cur)
{
	ChunkList *list;
	Chunk *chunk;

	BYTE *length;
	BYTE *name;
	BYTE *data;
	BYTE *crc;

	size_t l, i;

	length = (BYTE*)SafeMalloc(sizeof(BYTE)  *4);
	name = (BYTE*)SafeMalloc(sizeof(BYTE)  *4);
	crc = (BYTE*)SafeMalloc(sizeof(BYTE)  *4);

	length[0] = buffer[(*cur)++];
	length[1] = buffer[(*cur)++];
	length[2] = buffer[(*cur)++];
	length[3] = buffer[(*cur)++];

	name[0] = buffer[(*cur)++];
	name[1] = buffer[(*cur)++];
	name[2] = buffer[(*cur)++];
	name[3] = buffer[(*cur)++];

	l = CalculateLength(length);

	data = (BYTE*)SafeMalloc(sizeof(BYTE)  *l);

	for(i = 0; i < l; i++)
	{
		data[i] = buffer[(*cur)++];
	}

	crc[0] = buffer[(*cur)++];
	crc[1] = buffer[(*cur)++];
	crc[2] = buffer[(*cur)++];
	crc[3] = buffer[(*cur)++];

	chunk = (Chunk*)SafeMalloc(sizeof(Chunk));
	chunk->crc = crc;
	chunk->length = length;
	chunk->name = name;
	chunk->data = data;

	list = (ChunkList*)SafeMalloc(sizeof(ChunkList));
	list->next = NULL;

	list->item = chunk;

	return list;
}

void ReleaseChunk(Chunk *chunk)
{
	if(chunk != NULL)
	{
		free(chunk->crc);
		free(chunk->length);
		free(chunk->name);
		free(chunk->data);
		free(chunk);
	}
}

void ReleaseChunkList(ChunkList *list)
{
	if(list != NULL)
	{
		ReleaseChunkList(list->next);
		ReleaseChunk(list->item);
		free(list);
	}
}

void ReleasePNG(PNG* png)
{
	ReleaseChunkList(png->head);
	free(png);
}
